﻿using Ninject;
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;
using Peninsula.Utility.Extensions;

namespace Peninsula.DataAccess.EF
{
    public class EFBaseRepository<TEntity> : IRepository<TEntity> where TEntity : BaseEntity
    {
        #region 私有成员

        private void SetEntityCommonProperty(TEntity entity, bool isCreating, bool updateTime = true)
        {
            if (isCreating)
            {
                entity.Id = entity.Id.IfNullOrWhiteSpace(Guid.NewGuid().ToString());
                entity.CreatedTime = DateTime.Now;
                entity.CreatedBy = entity.CreatedBy.IfNullOrWhiteSpace("system");
            }
            if (updateTime)
            {
                entity.UpdatedTime = DateTime.Now;
            }
            entity.UpdatedBy = entity.UpdatedBy.IfNullOrWhiteSpace("system");
        }

        private DbSet<TEntity> EntitiesSet
        {
            get { return TestEFContexts.Set<TEntity>(); }
        }


        #endregion

        #region 属性

        [Inject]
        public TestEFContext TestEFContexts { get; set; }
        ////public TestEFContext TestEFContexts = new ExpressEFMysqlDbcontext();
        //static WindsorContainer container = WindsorInit.GetContainer();
        //ICharge charge = container.Resolve<ICharge>(new Arguments(new { }));
        //TestEFContext TestEFContexts = container.Resolve< TestEFContext>(new Arguments(new { }));


        /// <summary>
        ///     获取 当前实体的查询数据集
        /// </summary>
        public virtual IQueryable<TEntity> Entities
        {
            get { return TestEFContexts.Set<TEntity>(); }
        }


        #endregion

        #region 公共方法



        /// <summary>
        /// 是否存在
        /// </summary>
        /// <param name="query"></param>
        /// <returns></returns>
        public bool IsExist(IQueryable<TEntity> query)
        {
            return query.Select(u => u.Id).Count() > 0;
        }

        /// <summary>
        /// 是否存在
        /// </summary>
        /// <param name="predicate"></param>
        /// <returns></returns>
        public bool IsExist(Expression<Func<TEntity, bool>> predicate = null)
        {
            var query = Entities;
            if (predicate.IsNotNull())
            {
                query = query.Where(predicate);
            }
            return IsExist(query);
        }

        /// <summary>
        ///     插入实体记录
        /// </summary>
        /// <param name="entity"> 实体对象 </param>
        /// <param name="isSave"> 是否执行保存 </param>
        /// <returns> 操作影响的行数 </returns>
        public virtual int Insert(TEntity entity, bool isSave = true)
        {
            try
            {
                SetEntityCommonProperty(entity, true);
                EntitiesSet.Add(entity);
                return isSave ? TestEFContexts.SaveChanges() : 0;
            }
            catch (System.Data.Entity.Validation.DbEntityValidationException ex)
            {
                throw ex;
            }
            catch (Exception ex)
            {
                throw ex.InnerException;
            }
        }

        /// <summary>
        ///     批量插入实体记录集合
        /// </summary>
        /// <param name="entities"> 实体记录集合 </param>
        /// <param name="isSave"> 是否执行保存 </param>
        /// <returns> 操作影响的行数 </returns>
        public virtual int Insert(IEnumerable<TEntity> entities, bool isSave = true)
        {
            var _entities = EntitiesSet;
            entities.ForEach(o =>
            {
                SetEntityCommonProperty(o, true);
                _entities.Add(o);
            });
            //EFContext.BulkInsert(entities);

            return isSave ? TestEFContexts.SaveChanges() : 0;
        }

        public virtual void BulkInsert(IEnumerable<TEntity> entities, bool isSave = true)
        {
            entities.ForEach(o => SetEntityCommonProperty(o, true));
            TestEFContexts.BulkInsert(entities);
            if (isSave) TestEFContexts.BulkSaveChanges();
        }


        /// <summary>
        ///     删除指定编号的记录
        /// </summary>
        /// <param name="id"> 实体记录编号 </param>
        /// <param name="isSave"> 是否执行保存 </param>
        /// <returns> 操作影响的行数 </returns>
        public virtual int Delete(string id, bool isSave = true)
        {
            var entity = EntitiesSet.Find(id);
            return Delete(entity, isSave);
        }

        /// <summary>
        ///     删除实体记录
        /// </summary>
        /// <param name="entity"> 实体对象 </param>
        /// <param name="isSave"> 是否执行保存 </param>
        /// <returns> 操作影响的行数 </returns>
        public virtual int Delete(TEntity entity, bool isSave = true)
        {
            var entities = EntitiesSet;
            if (!entities.Local.Contains(entity))
            {
                TestEFContexts.Entry(entity).State = EntityState.Deleted;
            }
            else
            {
                entities.Remove(entity);
            }
            return isSave ? TestEFContexts.SaveChanges() : 0;
        }

        /// <summary>
        ///     删除实体记录集合
        /// </summary>
        /// <param name="entities"> 实体记录集合 </param>
        /// <param name="isSave"> 是否执行保存 </param>
        /// <returns> 操作影响的行数 </returns>
        public virtual int Delete(IEnumerable<TEntity> entities, bool isSave = true)
        {
            var _entities = EntitiesSet;
            entities.ForEach(o => _entities.Remove(o));
            return isSave ? TestEFContexts.SaveChanges() : 0;
        }

        /// <summary>
        ///     删除所有符合特定表达式的数据
        /// </summary>
        /// <param name="predicate"> 查询条件谓语表达式 </param>
        /// <param name="isSave"> 是否执行保存 </param>
        /// <returns> 操作影响的行数 </returns>
        public virtual int Delete(Expression<Func<TEntity, bool>> predicate, bool isSave = true)
        {
            IQueryable<TEntity> query = EntitiesSet;
            if (predicate != null)
                query = query.Where(predicate);
            return Delete(query.AsEnumerable(), isSave);
        }

        /// <summary>
        ///     更新实体记录
        /// </summary>
        /// <param name="entity"> 实体对象 </param>
        /// <param name="isSave"> 是否执行保存 </param>
        /// <returns> 操作影响的行数 </returns>
        public virtual int Update(TEntity entity, Func<TEntity, object[]> getKeys = null, bool isSave = true, bool updateTime = true)
        {

            if (getKeys.IsNull())
            {
                getKeys = o => new object[] { o.Id };
            }

            SetEntityCommonProperty(entity, false, updateTime);

            var entry = TestEFContexts.Entry(entity);

            if (entry.State == EntityState.Detached)
            {
                var entities = EntitiesSet;
                var keys = getKeys(entity);
                var currentEntry = entities.Find(keys);
                if (currentEntry != null)
                {
                    var attachedEntry = TestEFContexts.Entry(currentEntry);
                    attachedEntry.CurrentValues.SetValues(entity);
                    attachedEntry.State = EntityState.Modified;
                }
                else
                {
                    entities.Attach(entity);
                    entry.State = EntityState.Modified;
                }
            }
            return isSave ? TestEFContexts.SaveChanges() : 0;
        }


        /// <summary>
        /// 
        /// </summary>
        /// <param name="predicate"></param>
        /// <param name="setter"></param>
        /// <param name="saveChange"></param>
        /// <returns></returns>
        public int Update(Expression<Func<TEntity, bool>> predicate, Func<TEntity, TEntity> setter, bool isSave = true)
        {

            IQueryable<TEntity> query = EntitiesSet;
            if (predicate != null)
                query = query.Where(predicate);

            query.ForEach(obj =>
            {
                setter(obj);
                SetEntityCommonProperty(obj, false);
            });
            return isSave ? TestEFContexts.SaveChanges() : 0;
        }

        public void BulkUpdate(IEnumerable<TEntity> entities, bool isSave = true)
        {
            entities.ForEach(e => SetEntityCommonProperty(e, false));
            TestEFContexts.BulkUpdate(entities);
            if (isSave) TestEFContexts.BulkSaveChanges();
        }


        /// <summary>
        /// 批量更新
        /// </summary>
        /// <param name="predicate"></param>
        /// <param name="setter"></param>
        /// <param name="isSave"></param>
        public void BulkUpdate(Expression<Func<TEntity, bool>> predicate, Expression<Func<TEntity, TEntity>> setter, bool isSave = true)
        {
            IQueryable<TEntity> query = EntitiesSet;
            if (predicate != null)
                query = query.Where(predicate);
            query.UpdateFromQuery(setter);
            if (isSave) TestEFContexts.BulkSaveChanges();
        }

        /// <summary>
        ///     查找指定主键的实体记录
        /// </summary>
        /// <param name="id"> 指定主键 </param>
        /// <returns> 符合编号的记录，不存在返回null </returns>
        public virtual TEntity GetById(string id)
        {
            return EntitiesSet.Find(id);
        }

        /// <summary>
        /// 根据条件查询
        /// </summary>
        /// <param name="predicate"></param>
        /// <returns></returns>
        public TEntity Get(Expression<Func<TEntity, bool>> predicate)
        {
            return Entities.Where(predicate).FirstOrDefault();
        }

        /// <summary>
        /// 执行sql操作
        /// </summary>
        /// <param name="sql"></param>
        /// <returns></returns>
        public int ExecuteNonQuery(string sql)
        {
            return TestEFContexts.Database.ExecuteNonQuery(sql);
        }

        public List<T> QuerySql<T>(string sql, params object[] parameters)
        {
            return TestEFContexts.Database.SqlQuery<T>(sql, parameters).ToList();
        }

        public int ExecuteSqlCommand(string sql, params object[] parameters)
        {
            return TestEFContexts.Database.ExecuteSqlCommand(sql, parameters);
        }

        /// <summary>
        /// 保存变动
        /// </summary>
        /// <returns></returns>
        public virtual int SaveChanges()
        {
            return TestEFContexts.SaveChanges();
        }
        #endregion
    }

}
